/**
 * Epik_Controller.cpp
 * @author justin.drobey@gmail.com
 */
#include "Epik_Controller.h"
#include <pspctrl.h>
#include <pspthreadman.h>
#include <pspkerneltypes.h>

//DEFINE for the debugging in UpdateControl
#define IIF(a,b,c) ((a)? b:c)

// Declaration of the thread function.
int ControllerThread(SceSize args, void *argp);

/**
 * Constructor()
 * @param A pointer to a bool that turns false when the thread should stop.
 * @param The sleep time after the buttons have been read.
 *
 * The vars are initialized, and the pointer table's values are set to the
 * useless_ pointer.
 */
Epik_Controller::Epik_Controller(bool *run, unsigned int readDelay)
	:delay_(readDelay)
{
	running_ = run;
	useless_ = false;
	threadRun_ = false;
	pButtons_ = new bool *[NUM_BUTTONS__];

	for( int i=0; i<NUM_BUTTONS__; i++ )
		pButtons_[i] = &useless_;
		
	sceCtrlSetSamplingCycle(0);
	sceCtrlSetSamplingMode(1);
}


/**Destructor
 * Basically only stops the thread.
 */
Epik_Controller::~Epik_Controller() {
	Stop();

	delete [] pButtons_;
	delete Lx_;
	delete Ly_;
}


/**UpdateButtons()
 * This function reads all the buttons and sets the boolean values accordingly.
 */
u32 Epik_Controller::UpdateButtons() {
	SceCtrlData pad;
	sceCtrlPeekBufferPositive(&pad, 1);	// 1 = read pad once

	*(pButtons_[DPAD_UP]) = (pad.Buttons & PSP_CTRL_UP) != 0;
	*(pButtons_[DPAD_DOWN]) = (pad.Buttons & PSP_CTRL_DOWN) != 0;
	*(pButtons_[DPAD_LEFT]) = (pad.Buttons & PSP_CTRL_LEFT) != 0;
	*(pButtons_[DPAD_RIGHT]) = (pad.Buttons & PSP_CTRL_RIGHT) != 0;
	*(pButtons_[HUB_START]) = (pad.Buttons & PSP_CTRL_START) != 0;
	*(pButtons_[HUB_SELECT]) = (pad.Buttons & PSP_CTRL_SELECT) != 0;
	*(pButtons_[BTN_TRIANGLE]) = (pad.Buttons & PSP_CTRL_TRIANGLE) != 0;
	*(pButtons_[BTN_CROSS]) = (pad.Buttons & PSP_CTRL_CROSS) != 0;
	*(pButtons_[BTN_SQUARE]) = (pad.Buttons & PSP_CTRL_SQUARE) != 0;
	*(pButtons_[BTN_CIRCLE]) = (pad.Buttons & PSP_CTRL_CIRCLE) != 0;
	*(pButtons_[TRIGGER_LEFT]) = (pad.Buttons & PSP_CTRL_LTRIGGER) != 0;
	*(pButtons_[TRIGGER_RIGHT]) = (pad.Buttons & PSP_CTRL_RTRIGGER) != 0;

//	*Lx_ = ((int)((float)((float)((int)pad.Lx-128)/128.0f))*10)*10;
//	*Ly_ = ((int)((float)((float)(pad.Ly-128)/128.0f))*10)*10;

	return pad.Buttons;
}


/**void BindButton()
 * @param The button you want to intercept.
 * @param A pointer to a variable you want to store the button value in.
 */
void Epik_Controller::BindButton(enum Epik_Controller::BUTTONS pos, void *ptr) {
//	if( pos==STICK_AXISX )
//		Lx_ = reinterpret_cast<u8 *>(ptr);
//	else if( pos==STICK_AXISY )
//		Ly_ = reinterpret_cast<u8 *>(ptr);
//	else
	pButtons_[pos] = reinterpret_cast<bool *>(ptr);
}


/**bool isRunning() const
 * @return Returns TRUE if the thread is running.
 */
bool Epik_Controller::isRunning() const
{ return (*running_) && threadRun_; }


/**unsigned int GetDelay() const
 * @return Returns the current delay setting.
 */
unsigned int Epik_Controller::GetDelay() const
{ return delay_; }


/**void Start()
 * Creates then starts the thread.
 */
void Epik_Controller::Start() {
	if (!threadRun_)
	{
		threadRun_ = true;
		thid_ = sceKernelCreateThread("controller", ControllerThread, 0x20, 1024/*sizeof(*this)*/, 0, NULL);	// Trying at 1k
		
		u32 err = sceKernelStartThread(thid_, sizeof(*this), (void *)this);
	}
}


/**void Stop()
 * Stops the currently running thread.
 */
void Epik_Controller::Stop()
{	threadRun_ = false;	}


unsigned int Epik_Controller::Buttons() const
{	return buttons_;	}


// Thread function
int ControllerThread(SceSize args, void *argp) {
	Epik_Controller *ctrl = reinterpret_cast<Epik_Controller *>(argp);
	
	do
	{
		ctrl->UpdateButtons();
		sceKernelDelayThread(ctrl->GetDelay());
	} while( ctrl->isRunning() );

	sceKernelExitDeleteThread(0);
	return 0;
}
